﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;

namespace Kyoh.Lib.Text
{
    /// <summary><see cref="Encoding"/> の <see cref="TypeConverter"/> を提供します。</summary>
    public class EncodingTypeConverter : TypeConverter
    {
        /// <summary><see cref="GetStandardValues"/> メソッドを使用できるかどうかを取得します。</summary>
        /// <param name="context">書式指定コンテキストを提供する <see cref="ITypeDescriptorContext"/>。</param>
        /// <returns><see cref="GetStandardValues"/> メソッドを使用できる場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>標準的な <see cref="Encoding"/> のリストを格納する <see cref="TypeConverter.StandardValuesCollection"/> オブジェクトを取得します。</summary>
        /// <param name="context">書式指定コンテキストを提供する <see cref="ITypeDescriptorContext"/>。</param>
        /// <returns>有効値の標準セットを保持している <see cref="TypeConverter.StandardValuesCollection"/>。データ型が標準値セットをサポートしていない場合は <c>null</c>。</returns>
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            List<Encoding> stdValues = new List<Encoding>();
            foreach (var info in Encoding.GetEncodings())
                stdValues.Add(info.GetEncoding());
            return new StandardValuesCollection(stdValues);
        }

        /// <summary><see cref="GetStandardValues"/> メソッドのリストが、使用できるオブジェクトの排他的なリストであるかどうかを取得します。</summary>
        /// <param name="context">型変換のコンテキストを表す <see cref="ITypeDescriptorContext"/> 。</param>
        /// <remarks>この値が true の場合、PropertyGrid などの画面において、自由な文字列入力はできなくなります（選択肢のみになる）。</remarks>
        /// <returns><see cref="GetStandardValues"/> メソッドのリストが、使用できるオブジェクトの排他的なリストである場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return false;
        }

        /// <summary>指定された型からの変換をサポートするかどうかを取得します。</summary>
        /// <param name="context">型変換のコンテキストを表す <see cref="ITypeDescriptorContext"/> 。</param>
        /// <param name="sourceType">変換元の型を表す <see cref="Type"/>。</param>
        /// <returns>指定された型からの変換をサポートする場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return (sourceType == typeof(string));
        }

        /// <summary>指定された型への変換をサポートするかどうかを取得します。</summary>
        /// <param name="context">型変換のコンテキストを表す <see cref="ITypeDescriptorContext"/> 。</param>
        /// <param name="destinationType">変換先の型を表す <see cref="Type"/>。</param>
        /// <returns>指定された型への変換をサポートする場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return (destinationType == typeof(string) || destinationType == typeof(Encoding));
        }

        /// <summary>オブジェクトを <see cref="Encoding"/> オブジェクトに変換します。</summary>
        /// <param name="context">型変換のコンテキストを表す <see cref="ITypeDescriptorContext"/> 。</param>
        /// <param name="culture">現在のカルチャとして使用する <see cref="CultureInfo"/>。</param>
        /// <param name="value">変換元のオブジェクト。</param>
        /// <returns>変換結果の <see cref="Encoding"/>。</returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string a = value as string;
            if (string.IsNullOrEmpty(a))
                return null;
            else
                return Encoding.GetEncoding(a);
        }

        /// <summary>指定された型へ変換します。</summary>
        /// <param name="context">型変換のコンテキストを表す <see cref="ITypeDescriptorContext"/> 。</param>
        /// <param name="culture">現在のカルチャとして使用する <see cref="CultureInfo"/>。</param>
        /// <param name="value">変換元のオブジェクト。</param>
        /// <param name="destinationType">変換先の型を表す <see cref="Type"/>。</param>
        /// <returns>変換結果のオブジェクト。</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                Encoding t = (Encoding)value;
                if (t == null)
                    return null;
                else
                    return t.BodyName;
            }
            else if (destinationType == typeof(Encoding))
                return value;

            return null;
        }
    }
}